package com.aliyun.gts.sso.filter;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.aliyun.gts.sso.constant.SFSSOLoginConstants;
import com.aliyun.gts.sso.domain.CookieDTO;
import com.aliyun.gts.sso.domain.LoginAccount;
import com.aliyun.gts.sso.domain.TicketResponse;
import com.aliyun.gts.sso.boot.SFSSOLoginProperties;
import com.aliyun.gts.sso.util.SFSSOLoginUtils;
import com.aliyun.gts.sso.util.JwtTokenUtils;
import io.jsonwebtoken.Claims;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.cors.CorsUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.WebUtils;

//import javax.servlet.http.Cookie;
import jakarta.servlet.http.Cookie;

import java.io.IOException;

import static com.aliyun.gts.sso.constant.SFSSOLoginConstants.*;

/**
 * Created by 鸿度 on 2024-06-18 17:07.
 */
@Slf4j
public class SFSSOFilter extends OncePerRequestFilter {

    private final AntPathMatcher antPathMatcher = new AntPathMatcher();

    private static final RestTemplate restTemplate = new RestTemplate();

    @Autowired
    private SFSSOLoginProperties sfSSOLoginProperties;

//    @Override
//    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
//        String reqUri = SFSSOLoginUtils.getRequestURI(request);
//        if (CorsUtils.isPreFlightRequest(request) || ignoreUriPattern(reqUri)) {
//            chain.doFilter(request, response);
//            return;
//        }
//        if (reqUri.equals("/logout")) {
//            CookieDTO cookieDTO = new CookieDTO();
//            cookieDTO.setName(cookieName());
//            cookieDTO.setValue("");
//            cookieDTO.setDomain(sfSSOLoginProperties.getHost());
//            cookieDTO.setMaxAge(0);
//            cookieDTO.setHttpOnly(true);
//            if (SCHEMA_HTTPS.equalsIgnoreCase(sfSSOLoginProperties.getSchema())) {
//                cookieDTO.setSecure(true);
//            }
//            response.addHeader(SET_COOKIE_NAME, cookieDTO.generateCookieHeader());
//            String logoutUrl = SFSSOLoginUtils.builderLogoutRedirectURL(sfSSOLoginProperties);
//            response.sendRedirect(logoutUrl);
//            return;
//        }
//        if (reqUri.equals("/loginCallback")) {
//            String ticket = request.getParameter("ticket");
//            byte[] userinfoBytes = restTemplate.getForObject(sfSSOLoginProperties.getUrl() + "/api/sso/validate?ticket=" + ticket, byte[].class);
//            TicketResponse ticketResponse = JSON.parseObject(userinfoBytes, TicketResponse.class);
//            LoginAccount loginAccount = ticketResponse.getData();
//            CookieDTO cookieDTO = buildCookie(loginAccount);
//            response.addHeader(SET_COOKIE_NAME, cookieDTO.generateCookieHeader());
//            String returnURL = request.getParameter("callbackUrl");
//            String html = SFSSOLoginUtils.build302RedirectHtml(returnURL);
//            SFSSOLoginUtils.sendHtmlText(response, html);
//            return;
//        }
//        Cookie loginCookie = WebUtils.getCookie(request, cookieName());
//        Claims claims = JwtTokenUtils.parseJwtTokenClaims(loginCookie);
//        if (claims == null) {
//            String loginRedirectURL = SFSSOLoginUtils.builderLoginRedirectURL(sfSSOLoginProperties, request);
//            response.sendRedirect(loginRedirectURL);
//            return;
//        }
//        LoginAccount accountDTO = JSON.parseObject(claims.getSubject(), LoginAccount.class);
//        request.setAttribute(SFSSOLoginConstants.REQUEST_ATTR_LOGIN_ACCOUNT_INFO, accountDTO);
//        if (System.currentTimeMillis() - claims.getIssuedAt().getTime() > 3600 * 1000) {
//            CookieDTO cookieDTO = buildCookie(accountDTO);
//            response.addHeader(SET_COOKIE_NAME, cookieDTO.generateCookieHeader());
//        }
//        chain.doFilter(request, response);
//    }

    private CookieDTO buildCookie(LoginAccount loginAccount) {
        String jwtToken = JwtTokenUtils.generateJwtToken(JSON.toJSONString(loginAccount));
        CookieDTO cookieDTO = new CookieDTO();
        cookieDTO.setName(cookieName());
        cookieDTO.setValue(jwtToken);
        cookieDTO.setDomain(sfSSOLoginProperties.getHost());
        cookieDTO.setMaxAge(24 * 3600);
        cookieDTO.setHttpOnly(true);
        if (SCHEMA_HTTPS.equalsIgnoreCase(sfSSOLoginProperties.getSchema())) {
            cookieDTO.setSecure(true);
        }
        return cookieDTO;
    }

    private boolean ignoreUriPattern(String reqUri) {
        if (sfSSOLoginProperties.getIgnoreUriPatterns() == null) {
            return false;
        }
        for (String skipUriPattern : sfSSOLoginProperties.getIgnoreUriPatterns()) {
            if (antPathMatcher.match(skipUriPattern, reqUri)) {
                return true;
            }
        }
        return false;
    }

    private String cookieName() {
        return COOKIE_PREFIX + sfSSOLoginProperties.getHost();
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
        String reqUri = SFSSOLoginUtils.getRequestURI(request);
        if (CorsUtils.isPreFlightRequest(request) || ignoreUriPattern(reqUri)) {
            chain.doFilter(request, response);
            return;
        }
        if (reqUri.equals("/api/v1/logout")) {
            CookieDTO cookieDTO = new CookieDTO();
            cookieDTO.setName(cookieName());
            cookieDTO.setValue("");
            cookieDTO.setDomain(sfSSOLoginProperties.getHost());
            cookieDTO.setMaxAge(0);
            cookieDTO.setHttpOnly(true);
            if (SCHEMA_HTTPS.equalsIgnoreCase(sfSSOLoginProperties.getSchema())) {
                cookieDTO.setSecure(true);
            }
            response.addHeader(SET_COOKIE_NAME, cookieDTO.generateCookieHeader());
            String logoutUrl = SFSSOLoginUtils.builderLogoutRedirectURL(sfSSOLoginProperties);
            response.sendRedirect(logoutUrl);
            return;
        }
        if (reqUri.equals("/api/v1/loginCallback")) {
            String ticket = request.getParameter("ticket");
            byte[] userinfoBytes = restTemplate.getForObject(sfSSOLoginProperties.getUrl() + "/api/sso/validate?ticket=" + ticket, byte[].class);
            TicketResponse ticketResponse = JSON.parseObject(userinfoBytes, TicketResponse.class);
            LoginAccount loginAccount = ticketResponse.getData();
            JSONObject json = new JSONObject();
            if (loginAccount == null) {
                json.put("message", "ticket error");
                json.put("status", 402);
            } else {
                json.put("message", loginAccount);
                json.put("status", 200);
                CookieDTO cookieDTO = buildCookie(loginAccount);
                response.addHeader(SET_COOKIE_NAME, cookieDTO.getName() + "=" + cookieDTO.getValue());
            }
            response.setContentType("text/html;charset=UTF-8");
            response.getWriter().write(json.toJSONString());
            return;
        }
        Claims claims=null;
        if(StringUtils.isNotEmpty(request.getHeader("Authorization"))){
            String authorization= request.getHeader("Authorization");
            claims  =   JwtTokenUtils.parseJwtTokenClaims(authorization);
        }
        Cookie loginCookie = WebUtils.getCookie(request, cookieName());
        if(loginCookie!=null){
            claims = JwtTokenUtils.parseJwtTokenClaims(loginCookie);
        }
        if (claims == null) {
            JSONObject json = new JSONObject();
            json.put("message", "Not logged in, please log in first");
            json.put("status", 401);
            response.setContentType("text/html;charset=UTF-8");
            response.getWriter().write(json.toJSONString());
            return;
        }
        LoginAccount accountDTO = JSON.parseObject(claims.getSubject(), LoginAccount.class);
        request.setAttribute(SFSSOLoginConstants.REQUEST_ATTR_LOGIN_ACCOUNT_INFO, accountDTO);
        request.setAttribute(SFSSOLoginConstants.REQUEST_ATTR_LOGIN_STATUS_INFO, 200);

        if (System.currentTimeMillis() - claims.getIssuedAt().getTime() > 3600 * 1000) {//如果过期则创建
            CookieDTO cookieDTO = buildCookie(accountDTO);
            response.addHeader(SET_COOKIE_NAME, cookieDTO.generateCookieHeader());
        }
        chain.doFilter(request, response);
    }
}
